<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>接口测试</title>

    <script src="jquery_1.4.min.js"></script>
    <script src="pb_js.js"></script>

    <style>
        #wsAddress {
            width: 280px;
            height: 30px;
            font-size: 20px;
        }

        .wsAddress-btn-group {
            display: inline-block;
        }

        .output-style {
            overflow: auto;
            border: 1px solid black;
            height: 600px;
            margin: 10px 0;
        }

        .select-style {
            height: 30px;
            font-size: 20px;
        }

        #output {
            background-color: #c6ddaa
        }

        .bubble {
            white-space: pre;
        }

        #clearOutputButton {
            margin-left: 450px;
            width: 100px;
            height: 60px
        }
    </style>

</head>
<body>
<div id="main">
    <input type="text" id="wsAddress">
    <div class="wsAddress-btn-group">
        <button type="button" id="connectButton" onclick="app.connectWebsocket()">连接</button>
        <button type="button" id="closeButton" onclick="app.closeWebsocket()">断开</button>
        <button type="button" id="clearButton" onclick="app.clearWsAddress()">清空</button>
        <button type="button" id="clearOutputButton" onclick="$('#output').empty()">清空响应内容</button>
    </div>

    <div id="message-main">
        <div id="output" class="output-style"></div>
        <div id="select-main">
            <select id="folder-select" class="select-style" onchange="folderSelectChange()"></select>
            <select id="api-select" class="select-style" onchange="apiSelectChange()"></select>
        </div>

        <div id="params-main"></div>

        <button type="button" id="sendRequest" onclick="app.sendRequest()" style="margin-top: 10px">发送请求</button>

    </div>
</div>

</div>

<script>
    var app = {
        // ws默认地址
        defaultWebsocketAddress: "ws://10.0.0.153:8001/gateway",
        // websocket链接对象
        websocket: null,

        // 设置默认ws地址
        setPlaceholder: function (val) {
            _obj = $("#wsAddress")
            if (val == null) {
                val = this.defaultWebsocketAddress
            }
            _obj.attr({
                "placeholder": val,
                "value": val
            })

        },

        // 清空ws地址输入框
        clearWsAddress: function () {
            $("#wsAddress").val("")
        },

        // 链接websocket
        connectWebsocket: function () {
            if (this.websocket) {
                alert("websocket已连接")
                return
            }

            let _wsAddress = $("#wsAddress").val();
            if (_wsAddress == "") {
                alert("websocket地址不可为空")
                return;
            }

            this.websocket = new WebSocket(_wsAddress)
            NewWebSocket.call(this.websocket)
        },

        // 关闭websocket
        closeWebsocket: function () {
            if (this.websocket == null) {
                alert("请先连接websocket")
                return;
            }
            this.websocket.close()
        },

        // websocket链接成功
        onOpen: function () {
            app.writeMessage("<span style='color:red'>websocket连接成功!!</span>")
            folderSelectShow(true)
            apiSelectShow(true)
        },

        // 断开websocket
        onClose: function () {
            this.websocket = null
            folderSelectShow(false)
            apiSelectShow(false)
            this.writeMessage("<span style='color:red'>websocket连接断开!!</span>")
        },

        // websocket error
        onError: function (evt) {
            app.websocket = null
            app.writeMessage('<span style="color: red;">发生错误: ' + evt.data + '</span> ')
        },

        // 收到消息
        onMessage: function (evt) {
            let _recvData = evt.data
            let _recvType = typeof _recvData
            switch (_recvType) {
                case "object":
                    let reader = new FileReader()
                    reader.readAsArrayBuffer(_recvData)
                    reader.onload = function () {
                        let response = proto.Response.deserializeBinary(reader.result)
                        let _responseApi = response.getResponseapi()
                        let _responseStrMsg = response.getStringmsg()
                        // 直接读取StringMsg
                        if (_responseApi === "" && response.getS() === 0) {
                            _recvData = utf8to16(String.fromCharCode.apply(null, _responseStrMsg))
                            // _recvData = String.fromCharCode.apply(null, _responseStrMsg)
                            _recvData = JSON.parse(_recvData)
                            // if (typeof _recvData === "object"){
                            //     _recvData = JSON.stringify(_recvData, null, "\t")
                            // }
                        }
                        // 正常pb消息
                        else {
                            if (response.getS() !== 1) {
                                let _errInfo = {
                                    "s": response.getS(),
                                    "errorMsg": response.getErrormsg()
                                }
                                _recvData = _errInfo
                            } else {
                                let _responsePb = getResponsePb(_responseApi)
                                if (!_responsePb) {
                                    _recvData = _errInfo = {
                                        "s": response.getS(),
                                    }
                                } else {
                                    // 解序列any
                                    let anyData = response.getData()
                                    let responseAny = new proto.Any()
                                    responseAny.setTypeUrl(anyData.getTypeUrl())
                                    responseAny.setValue(anyData.getValue())
                                    let responseRes = responseAny.unpack(_responsePb.deserializeBinary, anyData.getTypeName())
                                    _recvData = responseRes.toObject()
                                }
                            }
                        }
                        _recvData = JSON.stringify(_recvData, null, "\t")
                        app.writeMessage('<span style="color:blue">服务端回应&nbsp;' + formatDate(new Date()) + '</span><br/><span class="bubble">' +
                            _recvData + '</span>');
                    }
                    break
                default:
                    _recvData = JSON.parse(_recvData)
                    if (typeof _recvData === "object"){
                        _recvData = JSON.stringify(_recvData, null, "\t")
                    }
                    this.writeMessage('<span style="color:blue">服务端回应&nbsp;' + formatDate(new Date()) + '</span><br/><span class="bubble">' +
                        _recvData + '</span>');
            }
        },

        // 写入消息
        writeMessage: function (message) {
            let messageDiv = '<div class="newMessage">' + message + ' </div>';
            let _outputDiv = $("#output");
            _outputDiv.append(messageDiv);
            let diffHeight = _outputDiv.attr("scrollHeight") - _outputDiv.attr("clientHeight")
            // 滚动条置底
            if (diffHeight) {
                _outputDiv.attr({
                    "scrollTop": diffHeight
                })
            }
        },

        _sendRequest: function (folder, api) {
            let _pb = getRequest(folder, api)
            app.websocket.send(_pb.serializeBinary())
        },

        // 发送请求
        sendRequest: function () {
            if (this.websocket == null) {
                alert("请先连接websocket")
                return;
            }

            let _folder = $("#folder-select").val()
            let _api = $("#api-select").val()
            if (_folder === "选择模块") {
                alert("请选择模块")
                return;
            }
            if (_api === "选择api") {
                alert("请选择api")
                return;
            }

            let _requestApi = _folder + "." + _api
            if (Api2Info[_requestApi] === undefined) {
                alert("该接口未定义无法请求")
                return;
            }

            // 设置请求参数参数
            for (let pId of requestParamsIds) {
                let _input = $('#' + pId)
                let _funcName = _input.attr("funcName")
                requestApi[_funcName](_input.val())
            }

            this._sendRequest(_folder, _api)

        }
    }

    function NewWebSocket() {
        // 链接成功
        this.onopen = function (evt) {
            app.onOpen()
        }
        // 链接关闭
        this.onclose = function (evt) {
            app.onClose()
        }
        // 收到消息
        this.onmessage = function (evt) {
            app.onMessage(evt)
        }
        // error
        this.onerror = function (evt) {
            app.onError(evt)
        }
    }


    // 禁用模块下拉
    function folderSelectShow(flag) {
        let _folder = $("#folder-select")
        if (flag) {
            _folder.removeAttr("disabled")
        } else {
            _folder.attr({
                "disabled": "disabled"
            })
        }
    }


    // 禁用api下拉
    function apiSelectShow(flag) {
        let api = $("#api-select")
        if (flag) {
            api.removeAttr("disabled")
        } else {
            api.attr({
                "disabled": "disabled"
            })
        }
    }

    // 模块选择
    function folderSelectChange() {
        let _folderSelect = $("#folder-select")
        let val = _folderSelect.val()
        CreateApiSelect(val)
    }

    // 生成api列表
    function CreateApiSelect(folder) {
        let _apiSelect = $("#api-select")
        // 清空select
        _apiSelect.empty()
        // 清空参数列表
        let paramsMain = $("#params-main")
        paramsMain.empty()

        let _apiList = Folder2Api[folder]
        if (_apiList !== undefined) {
            for (let api of _apiList) {
                _apiSelect.append('<option>' + api + '</option>')
            }
        } else {
            alert("【" + folder + "】" + "模块未定义api!!")
        }

        _apiSelect.append('<option selected="selected">' + "选择api" + '</option>')

    }


    // api选择
    function apiSelectChange() {
        let _folderSelect = $("#folder-select")
        let folderVal = _folderSelect.val()

        let _apiSelect = $("#api-select")
        let apiVal = _apiSelect.val()

        // 清空参数列表
        let paramsMain = $("#params-main")
        paramsMain.empty()

        // 生成api参数
        let _api = folderVal + "." + apiVal
        let apiArgs = getRequestArgs(_api)
        if (apiArgs) {
            requestApi = new apiArgs[0]()
            requestApi.name = apiArgs[1]
            requestParamsIds = []
            for (let key of Object.keys(requestApi.toObject())) {
                let _label = '<label style="margin-top: 5px">' + key + " " + '</label>'
                let _inputId = "params_" + key
                requestParamsIds.push(_inputId)
                let funcName = "set" + capitalizeFirstLetter(key)
                let _input = '<input funcName=' + funcName + ' style="margin-top: 5px" type="text" id=' + _inputId + '>'
                paramsMain.append(_label + _input + '<br>')
            }
        }

    }

    // 格式化日期格式
    function formatDate(now) {
        var year = now.getFullYear();
        var month = now.getMonth() + 1;
        var date = now.getDate();
        var hour = now.getHours();
        var minute = now.getMinutes();
        var second = now.getSeconds();
        return year + "-" + (month = month < 10 ? ("0" + month) : month) + "-" + (date = date < 10 ? ("0" + date) : date) +
            " " + (hour = hour < 10 ? ("0" + hour) : hour) + ":" + (minute = minute < 10 ? ("0" + minute) : minute) + ":" + (
                second = second < 10 ? ("0" + second) : second);
    }

    // 首字母大写
    function capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }

    function utf8to16(str) {
        let out, i, len, c;
        let char2, char3;
        out = "";
        len = str.length;
        i = 0;
        while (i < len) {
            c = str.charCodeAt(i++);
            switch (c >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    // 0xxxxxxx
                    out += str.charAt(i - 1);
                    break;
                case 12:
                case 13:
                    // 110x xxxx 10xx xxxx
                    char2 = str.charCodeAt(i++);
                    out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
                    break;
                case 14:
                    // 1110 xxxx 10xx xxxx 10xx xxxx
                    char2 = str.charCodeAt(i++);
                    char3 = str.charCodeAt(i++);
                    out += String.fromCharCode(((c & 0x0F) << 12) |
                        ((char2 & 0x3F) << 6) |
                        ((char3 & 0x3F) << 0));
                    break;
            }

        }

        return out;

    }


</script>

<script>
    var Folder2Api = {
        "user": [
            "Login",  // 登陆
            "GetInfo",  // 获取玩家数据
            "ChangeName",  // 修改玩家名
            "LvUp",  // 玩家升级
        ],
        "hero": [
            "GetList", // 获取英雄列表
            "GetInfo", // 获取英雄数据
        ],
        "item": [
            "GetList", // 获取物品列表
        ],
        "chat": [
            "SendMsg", // 发送聊天消息
        ],
        "task": [
            "Open", // 获取任务数据
            "Finish", // 完成任務
        ],
        "cross_user": [
            "GetInfo",  // 获取玩家跨服数据
        ],

    };
    var Api2Info = {
        // 获取玩家跨服数据
        "cross_user.GetInfo": {
            "args": [proto.UserGetInfoArgs, "UserGetInfoArgs"],
            "res": proto.UserGetInfoRes
        },
        // 登陆
        "user.Login": {
            "args": [proto.LoginArgs, "LoginArgs"],
            "res": proto.LoginRes
        },
        // 获取玩家数据
        "user.GetInfo": {
            "args": [proto.UserGetInfoArgs, "UserGetInfoArgs"],
            "res": proto.UserGetInfoRes
        },
        // 改名
        "user.ChangeName": {
            "args": [proto.ChangeNameArgs, "ChangeNameArgs"],
        },
        // 升级
        "user.LvUp": {
            "args": [proto.LvUpArgs, "LvUpArgs"],
        },
        // 获取英雄列表
        "hero.GetList": {
            "args": [proto.HeroGetListArgs, "HeroGetListArgs"],
            "res": proto.HeroGetListRes
        },
        // 获取英雄数据
        "hero.GetInfo": {
            "args": [proto.HeroGetInfoArgs, "HeroGetInfoArgs"],
            "res": proto.HeroGetInfoRes
        },
        // 获取物品列表
        "item.GetList": {
            "args": [proto.ItemGetListArgs, "ItemGetListArgs"],
            "res": proto.ItemGetListRes
        },
        // 发送聊天消息
        "chat.SendMsg": {
            "args": [proto.SendMsgArgs, "SendMsgArgs"]
        },
        // 获取任务数据
        "task.Open": {
            "args": [proto.TaskOpenArgs, "TaskOpenArgs"],
            "res": proto.TaskOpenRes
        },
        // 完成任务
        "task.Finish": {
            "args": [proto.TaskFinishArgs, "TaskFinishArgs"],
            "res": proto.TaskFinishRes
        },
    }

    // 请求的内容
    var requestApi
    var requestParamsIds = []

    // 获取请求头
    function getRequest(moduleName, apiName) {
        _request = new proto.Request()
        _request.setModulename(moduleName)
        _request.setApiname(apiName)

        // 请求参数
        let _anyData = new proto.Any()
        _anyData.pack(requestApi.serializeBinary(), requestApi.name)
        _request.setData(_anyData)

        return _request
    }

    // 获取请求参数
    function getRequestArgs(requestApi) {
        let apiInfo = Api2Info[requestApi]
        // 没有这个接口
        if (!apiInfo) {
            return null
        }
        return apiInfo.args
    }

    // 获取响应主体pb
    function getResponsePb(responseApi) {
        let apiInfo = Api2Info[responseApi]
        // 没有这个接口
        if (!apiInfo) {
            return null
        }
        return apiInfo.res
    }

</script>
<script>
    // 初始化
    function init() {
        app.setPlaceholder()


        // 增加调用模块
        let _folder = $("#folder-select")
        for (let folder in Folder2Api) {
            _folder.append('<option>' + folder + '</option>')
        }
        _folder.append('<option selected="selected">' + "选择模块" + '</option>')

        // 增加调用模块接口
        let _api = $("#api-select")
        _api.append('<option selected="selected">' + "选择api" + '</option>')
        _api.attr({
            "disabled": "disabled"
        })

        folderSelectShow(false)
        apiSelectShow(false)
    }

    init()

</script>
</body>
</html>